package com.jdzy.student.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jdzy.common.constants.CommonConstants;
import com.jdzy.common.constants.ResearchTopicConstants;
import com.jdzy.common.exception.DeleteException;
import com.jdzy.common.exception.InsertNullException;
import com.jdzy.model.common.dtos.PageRequestDto;
import com.jdzy.model.common.vos.PageResult;
import com.jdzy.model.common.vos.Result;
import com.jdzy.model.student.dtos.ResearchTopicDeleteDto;
import com.jdzy.model.student.dtos.ResearchTopicDto;
import com.jdzy.model.student.dtos.ResearchTopicSearchDto;
import com.jdzy.model.student.pojos.ResearchTopic;
import com.jdzy.model.student.pojos.ResearchTopicParticipant;
import com.jdzy.model.student.vos.ResearchTopicVo;
import com.jdzy.student.mapper.ResearchTopicMapper;
import com.jdzy.student.mapper.ResearchTopicParticipantMapper;
import com.jdzy.student.service.ResearchTopicService;
import com.jdzy.utils.common.ParseToListOrStringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.util.*;

@Service
@Slf4j
public class ResearchTopicServiceImpl extends ServiceImpl<ResearchTopicMapper, ResearchTopic> implements ResearchTopicService {

    @Autowired
    private ResearchTopicMapper researchTopicMapper;

    @Autowired
    private ResearchTopicParticipantMapper researchTopicParticipantMapper;


    /**
     * 获取课题信息
     *
     * @param stuId
     * @param page
     * @param size
     * @param researchTopicSearchDto
     * @return
     */
    @Override
    @Transactional
    public Result getResearchTopicByStuId(String stuId, Integer page, Integer size, ResearchTopicSearchDto researchTopicSearchDto) {
        //1、检查参数
        if(StringUtils.isBlank(stuId)){
            return Result.error(CommonConstants.PARAM_REQUIRE);
        }
        //设置分页
        PageRequestDto pageRequestDto=new PageRequestDto(page,size);
        pageRequestDto.checkParam();
        //分页查询
        IPage iPage=new Page(pageRequestDto.getPage(),pageRequestDto.getSize());

        //2、进行查询research_topic表
        LambdaQueryWrapper<ResearchTopic> researchTopicLambdaQueryWrapper = Wrappers.<ResearchTopic>lambdaQuery()
                .eq(ResearchTopic::getStuId, stuId)
                .like(StringUtils.isNotBlank(researchTopicSearchDto.getResearchTopicName()), ResearchTopic::getResearchTopicName, researchTopicSearchDto.getResearchTopicName())
                .eq(researchTopicSearchDto.getResearchTopicStatus() != null, ResearchTopic::getResearchTopicStatus, researchTopicSearchDto.getResearchTopicStatus())
                .eq(researchTopicSearchDto.getGrade() != null, ResearchTopic::getGrade, researchTopicSearchDto.getGrade())
                .eq(researchTopicSearchDto.getResearchField()!=null,ResearchTopic::getResearchField,researchTopicSearchDto.getResearchField())
                .like(StringUtils.isNotBlank(researchTopicSearchDto.getHostPerson()), ResearchTopic::getHostPerson, researchTopicSearchDto.getHostPerson())
                .ge(researchTopicSearchDto.getStartTime() != null, ResearchTopic::getStartTime, researchTopicSearchDto.getStartTime())
                .le(researchTopicSearchDto.getEndTime() != null, ResearchTopic::getEndTime, researchTopicSearchDto.getEndTime());

        //2.1、对于参与人进行查询(这里是精确查找)
        //2.1.1、看条件参数是否为空嘛
        String researchTopicParticipantStr = researchTopicSearchDto.getResearchTopicParticipantStr();
        if(StringUtils.isNotBlank(researchTopicParticipantStr)){
            //不为空则向数据库寻找

            List<String> researchTopicParticipants = ParseToListOrStringUtils
                    .parseToListWithString(researchTopicParticipantStr,ResearchTopicConstants.RESEARCH_TOPIC_SPILT);
            List<Long> researchTopicId = researchTopicParticipantMapper.getResearchTopicIdListByName(stuId, researchTopicParticipants);
            if(researchTopicId==null || researchTopicId.size()==0){
                return Result.success();
            }
            researchTopicLambdaQueryWrapper.in(ResearchTopic::getId,researchTopicId);
        }

        IPage selectPage = researchTopicMapper.selectPage(iPage, researchTopicLambdaQueryWrapper);
        List<ResearchTopic> researchTopics = selectPage.getRecords();

        //3、进行数据拷贝
        List<ResearchTopicVo> researchTopicVos=new ArrayList<>();
        for (ResearchTopic researchTopic : researchTopics) {
            ResearchTopicVo researchTopicVo=new ResearchTopicVo();
            BeanUtils.copyProperties(researchTopic,researchTopicVo);
            //从research_topic_participant表中获取参与人
            List<ResearchTopicParticipant> researchTopicParticipants = researchTopicParticipantMapper
                    .selectList(Wrappers.<ResearchTopicParticipant>lambdaQuery()
                            .eq(ResearchTopicParticipant::getResearchTopicId, researchTopic.getId()));
            //存储参与人姓名
            List<String> participants=new ArrayList<>();
            for (ResearchTopicParticipant researchTopicParticipant : researchTopicParticipants) {
                participants.add(researchTopicParticipant.getResearchTopicParticipantName());
            }
            //将参与人信息拷贝的vo类中

            /*
            将participants分装为String类型  并与前端商议好以逗号分割
             */

            researchTopicVo
                    .setResearchTopicParticipantStr(ParseToListOrStringUtils
                            .parseToString(participants,ResearchTopicConstants.RESEARCH_TOPIC_SPILT));

            //最后存储到vos中
            researchTopicVos.add(researchTopicVo);
        }
        //封装分页数据信息
        PageResult pageResult=new PageResult(pageRequestDto.getPage(),pageRequestDto.getSize(),iPage.getTotal());
        pageResult.setData(researchTopicVos);
        return pageResult;
    }

    /**
     * 获取课题信息
     *
     * @param stuId
     * @param researchTopicDeleteDto
     * @return
     */
    @Override
    @Transactional
    public Result deleteResearchTopic(String stuId, ResearchTopicDeleteDto researchTopicDeleteDto) {
        //1、检查参数
        if(StringUtils.isBlank(stuId) || researchTopicDeleteDto==null || researchTopicDeleteDto.getResearchTopicIds().isEmpty()){
            return Result.error(CommonConstants.PARAM_REQUIRE);
        }
        synchronized ("deleteResearchTopic"+CommonConstants.LOCK_INDEX +stuId){
            //2、进行删除ResearchTopic表中的数据
            try {
                int deleteResearchTopicNum = researchTopicMapper.delete(Wrappers.<ResearchTopic>lambdaQuery()
                        .eq(ResearchTopic::getStuId, stuId)
                        .in(ResearchTopic::getId, researchTopicDeleteDto.getResearchTopicIds()));
                if(deleteResearchTopicNum!=researchTopicDeleteDto.getResearchTopicIds().size()){
                    throw new DeleteException();
                }
            }catch (DeleteException deleteException){
                //手动回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                log.error("deleteResearchTopic，删除ResearchTopic表失败");
                return Result.error(CommonConstants.DELETE_FAIL);
            }

            try {
                //3、进行删除ResearchTopicParticipant表中的数据
                int deleteResearchTopicParticipant = researchTopicParticipantMapper.delete(Wrappers.<ResearchTopicParticipant>lambdaQuery()
                        .eq(ResearchTopicParticipant::getStuId, stuId)
                        .in(ResearchTopicParticipant::getResearchTopicId, researchTopicDeleteDto.getResearchTopicIds()));

                if(deleteResearchTopicParticipant!=researchTopicDeleteDto.getResearchTopicIds().size()){
                    throw new DeleteException();
                }
            }catch (DeleteException deleteException){
                //手动回滚
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                log.error("deleteResearchTopic，删除ResearchTopicParticipant表失败");
                return Result.error(CommonConstants.DELETE_FAIL);
            }

            return Result.success();
        }

    }

    /**
     * 新增课题信息
     * @param researchTopicDto
     * @return
     */
    @Override
    @Transactional
    public Result saveResearchTopic(ResearchTopicDto researchTopicDto) {
        //1、检查参数  学号和课题名称不可以为空
        if(researchTopicDto==null || StringUtils.isBlank(researchTopicDto.getStuId()) || StringUtils.isBlank(researchTopicDto.getResearchTopicName())){
            return Result.error(CommonConstants.PARAM_REQUIRE);
        }
        //2、插入到ResearchTopic表中
        //进行属性拷贝
        ResearchTopic researchTopic=new ResearchTopic();
        BeanUtils.copyProperties(researchTopicDto,researchTopic);
        //插入到数据库中
        int insertResearchTopicNum = researchTopicMapper.insert(researchTopic);
        if(insertResearchTopicNum==0){
            //插入失败
            return Result.error(CommonConstants.INSERT_FAIL);
        }

        //3、将参与者插入到ResearchTopicPaticipant表

        /*
        将researchTopicParticipantStr分割为researchTopicParticipants  与前端商议以","分割
         */
        researchTopicDto.setResearchTopicParticipants(
                ParseToListOrStringUtils.parseToListWithString(researchTopicDto
                        .getResearchTopicParticipantStr(),ResearchTopicConstants.RESEARCH_TOPIC_SPILT)
        );

        for (String researchTopicParticipantName : researchTopicDto.getResearchTopicParticipants()) {
            ResearchTopicParticipant researchTopicParticipant=new ResearchTopicParticipant();
            researchTopicParticipant.setStuId(researchTopic.getStuId());
            researchTopicParticipant.setResearchTopicId(researchTopic.getId());
            researchTopicParticipant.setResearchTopicParticipantName(researchTopicParticipantName);
            //进行插入到数据库中
            int insertResearchTopicParticipantNum = researchTopicParticipantMapper.insert(researchTopicParticipant);
            try {
                if(insertResearchTopicParticipantNum==0){
                    //插入失败 进行抛出错误并回滚事务
                    throw new InsertNullException();
                }
            }catch (InsertNullException insertNullException){
                //手动回滚事务
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                log.error("插入ResearchTopicPaticipant表信息失败,参数:{}",researchTopicParticipant);
                return Result.error(CommonConstants.INSERT_FAIL);
            }
        }
        //4、插入成功
        return Result.success();
    }

    /**
     * 修改课题信息
     * @param researchTopicDto
     * @return
     */
    @Override
    @Transactional
    public Result updateResearchTopic(ResearchTopicDto researchTopicDto) {
        //1、检查参数
        if(researchTopicDto==null || researchTopicDto.getId()==null || StringUtils.isBlank(researchTopicDto.getStuId())){
            return Result.error(CommonConstants.PARAM_REQUIRE);
        }
        //加锁 避免数据污染
        synchronized ("updateResearchTopic"+CommonConstants.LOCK_INDEX+researchTopicDto.getId()
                +CommonConstants.LOCK_INDEX+researchTopicDto.getStuId()){
            //2、先查询ResearchTopic数据库中有无这条数据
            ResearchTopic researchTopic = researchTopicMapper.selectOne(Wrappers.<ResearchTopic>lambdaQuery()
                    .eq(ResearchTopic::getId, researchTopicDto.getId())
                    .eq(ResearchTopic::getStuId, researchTopicDto.getStuId()));
            if(researchTopic==null){
                //此时数据库中不存在该条数据
                return Result.error(CommonConstants.DATASOURCE_IS_NULL);
            }
            //开始修改  进行数据拷贝
            BeanUtils.copyProperties(researchTopicDto,researchTopic);
            //进行修改
            int updateById = researchTopicMapper.updateById(researchTopic);
            if(updateById==0){
                //修改失败
                return Result.error(CommonConstants.UPDATE_FAIL);
            }

            /*
                将researchTopicParticipantStr分割为researchTopicParticipants  与前端商议以","分割
            */
            researchTopicDto.setResearchTopicParticipants(
                    ParseToListOrStringUtils.parseToListWithString(researchTopicDto
                            .getResearchTopicParticipantStr(),ResearchTopicConstants.RESEARCH_TOPIC_SPILT)
            );


            //3、修改成功  开始准备ResearchTopicParticipant表
            List<ResearchTopicParticipant> researchTopicParticipants = researchTopicParticipantMapper
                    .selectList(Wrappers.<ResearchTopicParticipant>lambdaQuery()
                            .eq(ResearchTopicParticipant::getResearchTopicId, researchTopicDto.getId())
                            .eq(ResearchTopicParticipant::getStuId, researchTopicDto.getStuId()));
            // 进判断是否有不一样的地方(即是否需要修改)
            //准备原本数据库中的名称
            Map<String,Integer> oldNames=new HashMap<>();
            for (ResearchTopicParticipant researchTopicParticipant : researchTopicParticipants) {
                String researchTopicParticipantName = researchTopicParticipant.getResearchTopicParticipantName();
                oldNames.put(researchTopicParticipantName,oldNames.getOrDefault(researchTopicParticipantName,0)+1);
            }
            //这是修改的新数据中的数据
            List<String> researchTopicParticipantsNames = researchTopicDto.getResearchTopicParticipants();
            Map<String,Integer> newNames=new HashMap<>();
            for (String researchTopicParticipantsName : researchTopicParticipantsNames) {
                newNames.put(researchTopicParticipantsName,newNames.getOrDefault(researchTopicParticipantsName,0)+1);
            }
            //开始进行判断
            if(oldNames.equals(newNames)){
                //不需要修改 直接返回结果即可
                return Result.success();
            }else{
                //需要进行修改  这里图方便直接将数据库中的删除了
                int deleteResearchTopicParticipantNum = researchTopicParticipantMapper
                        .delete(Wrappers.<ResearchTopicParticipant>lambdaQuery()
                                .eq(ResearchTopicParticipant::getResearchTopicId, researchTopicDto.getId())
                                .eq(ResearchTopicParticipant::getStuId, researchTopicDto.getStuId()));
                //判断是否删除成功了
                try {
                    if(deleteResearchTopicParticipantNum!=researchTopicParticipants.size()){
                        //删除数目对应不上  出现问题了 直接抛出异常 回滚事务
                        throw new DeleteException();
                    }
                }catch (DeleteException deleteException){
                    //回滚事务
                    TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                    log.error("修改事务错误,删除的ResearchTopicParticipant数量对不上数据库中原有的");
                    return Result.error(CommonConstants.UPDATE_FAIL);
                }
                //此时删除成功
                if(researchTopicDto.getResearchTopicParticipants().size()==0){
                    //无需新插入  直接返回即可
                    return Result.success();
                }else{
                    //重新插入数据
                    List<String> newResearchTopicParticipantsNames = researchTopicDto.getResearchTopicParticipants();
                    for (String newResearchTopicParticipantsName : newResearchTopicParticipantsNames) {
                        ResearchTopicParticipant researchTopicParticipant=new ResearchTopicParticipant();
                        researchTopicParticipant.setResearchTopicId(researchTopicDto.getId());
                        researchTopicParticipant.setStuId(researchTopicDto.getStuId());
                        researchTopicParticipant.setResearchTopicParticipantName(newResearchTopicParticipantsName);
                        int insert = researchTopicParticipantMapper.insert(researchTopicParticipant);
                        try {
                            if(insert==0){
                                //插入失败 回滚事务
                                throw new InsertNullException();
                            }
                        }catch (InsertNullException insertNullException){
                            //回滚事务
                            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                            log.error("新增失败到researchTopicParticipant表数据失败");
                            return Result.error(CommonConstants.UPDATE_FAIL);
                        }
                    }
                }
            }
            return Result.success();
        }

    }
}
